///////////////////////////////////////////////////////////////////////////////////////////////////
// Illusion Ray Development Kit (IDK)           Copyright (c) 2010 ( dimitriy.martynenko@gmail.com )
///////////////////////////////////////////////////////////////////////////////////////////////////
// Created : 2010-05-22
// Updated : ...
// Licence : NEW BSD
// Info	   : "SCL" Safe Code Lib (for C++ unmanaged)
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once

namespace Platform
{
	struct Config
	{
		enum Enum
		{
			// - ThreadSafeMode
			NoneThreadSafe = false,
			ThreadSafe = true,
			ThreadSafeMode = NoneThreadSafe,
			// - ThreadSafeMode
			ThreadLockMaxTimeIterationToSleep = 1000,
			ThreadLockSleepTimeInMs = 1
		};
	};

	struct OutputConsole
	{
		static void Message(const char* text);
	};

	struct Memory
	{
		template<typename T>
		static void Copy(const T* in, T* out, uint len)
		{
			for(uint i = 0; i != len; ++i)
				out[i] = in[i];
		}
	};

	struct Random
	{
		uint seed;

		Random() : seed(0x4F0C7947 + 0x5D588B65 * (uint)&seed) // seed must be a address variable
		{
		}

		template<typename T>
		inline T Rand(T max) 
		{ 
			return (T)((seed = 0x4F0C7947 + 0x5D588B65 * seed) * (float)max / 4294967296.0f); 
		}
	};

	struct Time
	{
		static unsigned long Get();
		static void Sleep(uint ms);
	};

	class FileHandle;


	//
	//
	//

	template<bool UseThreadSafe>
	class TRefCounter
	{
	private:
		TRefCounter(const TRefCounter&);
		TRefCounter& operator=(const TRefCounter&);
	public:
		TRefCounter() : mRefCount(0){}
		inline void AddRef(void);
		inline bool Release();
		inline bool IsUnique() const { return mRefCount == 1; }
		inline long GetCount() const { return mRefCount; }
	private:
		volatile long mRefCount;
	};

	template<>
	inline void TRefCounter<Config::NoneThreadSafe>::AddRef(void)
	{
		++mRefCount;
	}

	template<>
	inline bool TRefCounter<Config::NoneThreadSafe>::Release()
	{
		return (--mRefCount) == 0;
	}

	typedef TRefCounter<Config::ThreadSafeMode> RefCounter;


	//
	//
	//
	class Locker;

	//
	// Mutex
	//
	template<bool UseThreadSafe>
	class TMutex;

	template<>
	class TMutex<Config::NoneThreadSafe>
	{
	private:
		TMutex(const TMutex&);
		TMutex& operator=(const TMutex&);
	public:
		TMutex(const Locker&){}
	};

	typedef TMutex<Config::ThreadSafeMode> Mutex;

	//
	//
	//
	class Event;

	//
	//
	//
	class EventCondition;

	//
	// Thread Handle
	//
	class ThreadHandle; // provide thread Create, Close


	class Timer
	{
		typedef unsigned long TimePrecision;
	private:
		TimePrecision mPrevTime;
	public:
		inline Timer()
		{
			Start();
		}

		inline void Start(void)
		{			
			mPrevTime = Platform::Time::Get();
		}

		inline float GetElapsed(void)
		{
			TimePrecision currentTime = Platform::Time::Get();
			TimePrecision elapsedTime = currentTime - mPrevTime;
			mPrevTime = currentTime;

			float timetoFloat = (float)elapsedTime*0.001f;
			return timetoFloat;
		}
	};	
	//
	//
	//
	struct Profiler
	{
		RefCounter AllocCount;

		static Profiler& Get()
		{
			static Profiler inst;
			return inst;
		}
	};

	template<typename T>
	struct Math
	{
		static T Sqrt(T x);
		static T Sin(T x);
		static T Cos(T x);
		static T ArcTan2(T y, T x);
	};


	namespace InputSystem
	{
		template<typename TCode>
		struct Event
		{
			TCode code;

			typedef TCode Code;

			template<typename T>
			Event(T code)
				: code(static_cast<TCode>(code))
			{}
		};

		struct MouseCode
		{
			enum Enum
			{
				None,
				Left,
				Right
			};
		};

		struct MouseEvent : Event<MouseCode::Enum>
		{
			int x, y;
		public:
			MouseEvent(MouseCode::Enum code, int x, int y) : Event(code), x(x), y(y)
			{
			}
		};

		struct KeyboardCode
		{
			enum Enum
			{
				None = 0,
				A = 65, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
				//
				Esc = 27,
				Shift = 16,
				Ctrl = 17,
				Space = 32,
				//Arrow
				ArrowLeft = 37,
				ArrowUp = 38,
				ArrowRight = 39,
				ArrowDown = 40,
			};
		};

		typedef Event<KeyboardCode::Enum> KeyboardEvent;
	};

	class WindowHandle;
}

#if (defined(__SYMBIAN32__))
#       include <PlatformSymbian.hpp>
#elif (defined(__WIN32__)) || (defined(_WIN32))
#	include <PlatformWin32.hpp>
#elif (defined(__APPLE_CC__))
#	include <PlatformMacOS.hpp>
#endif

//#define DISABLE_LOG

#if (defined(DISABLE_LOG))
	#define iFunction               //do nothing
	#define iLog(X)					//do nothing
	#define iLogDebug(X)			//do nothing
	#define iLogDebug2(X)			//do nothing

	#define iDebug(X)				//do nothing

	#define iError(X)				throw;
	#define iAssert(X, Y)			if(!(X))	iError(Y);
#else
	//
	// hellper defines
	//
	//#define iFunction					Platform::OutputConsole::Message(" function "); Platform::OutputConsole::Message(__FUNCTION__);
	#define iFunction                   //do nothing
	#define iLog(X)						Platform::OutputConsole::Message("[IDK Log] : "); Platform::OutputConsole::Message(X); iFunction; Platform::OutputConsole::Message("\n");
	#define iLogDebug(X)				Platform::OutputConsole::Message(X); Platform::OutputConsole::Message("\n");
	#define iLogDebug2(X)				Platform::OutputConsole::Message(X);

	#if defined(DEBUG) | defined(_DEBUG)
	#	define iDebug(X) iLog(X)
	#else
	#	define iDebug(X)				//empty
	#endif

	#define iError(X)				{ Platform::OutputConsole::Message("[IDK Error]"X" in "); Platform::OutputConsole::Message(__FUNCTION__); Platform::OutputConsole::Message("\n"); throw; }
	#define iAssert(X, Y)			if(!(X))	iError(Y);
#endif

#define iStaticAssert(X)		typedef char __CASSERT__##__LINE__[(X) ? 1 : -1]

#define lock(x)					System::Platform::Mutex __lock(x)
